﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область СлужебныйПрограммныйИнтерфейс

// Обновляет группировки пользователей для проверки разрешенных значений
// по видам доступа Пользователи и ВнешниеПользователи.
//
// Требуется вызывать:
// 1) При добавлении нового пользователя        (или внешнего пользователя),
//    При добавлении новой группы пользователей (или группы внешних пользователей),
//    при изменении состава групп пользователей (или групп  внешних пользователей).
//    Параметры = Структура с одним из свойств или сразу двумя свойствами:
//    - Пользователи:        один пользователь или массив.
//    - ГруппыПользователей: одна группа пользователей или массив.
//
// 2) При изменении групп исполнителей.
//    Параметры = Структура с одним свойством:
//    - ГруппыИсполнителей: Неопределено, одна группа исполнителей или массив.
//
// 3) При изменении объекта авторизации внешнего пользователя.
//    Параметры = Структура с одним свойством:
//    - ОбъектыАвторизации: Неопределено, один объект авторизации или массив.
//
// Типы, используемые в параметрах:
//
//  Пользователь         - СправочникСсылка.Пользователи,
//                         СправочникСсылка.ВнешниеПользователи.
//
//  Группа пользователей - СправочникСсылка.ГруппыПользователей,
//                         СправочникСсылка.ГруппыВнешнихПользователей.
//
//  Исполнитель          - СправочникСсылка.Пользователи,
//                         СправочникСсылка.ВнешниеПользователи.
//
//  Группа исполнителей  - например, СправочникСсылка.ГруппыИсполнителейЗадач.
//
//  Объект авторизации   - например, СправочникСсылка.ФизическиеЛица.
//
// Параметры:
//  Параметры     - Неопределено - обновить все без отбора.
//                  см. варианты выше.
//
//  ЕстьИзменения - Булево - (возвращаемое значение) - если производилась запись,
//                  устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьГруппировкиПользователей(Параметры = Неопределено, ЕстьИзменения = Неопределено) Экспорт
	
	ВидОбновления = "";
	
	Если Параметры = Неопределено Тогда
		ВидОбновления = "Все";
	
	ИначеЕсли Параметры.Количество() = 2
	        И Параметры.Свойство("Пользователи")
	        И Параметры.Свойство("ГруппыПользователей") Тогда
		
		ВидОбновления = "ПользователиИГруппыПользователей";
		
	ИначеЕсли Параметры.Количество() = 1
	        И Параметры.Свойство("Пользователи") Тогда
		
		ВидОбновления = "ПользователиИГруппыПользователей";
		
	ИначеЕсли Параметры.Количество() = 1
	        И Параметры.Свойство("ГруппыПользователей") Тогда
		
		ВидОбновления = "ПользователиИГруппыПользователей";
		
	ИначеЕсли Параметры.Количество() = 1
	        И Параметры.Свойство("ГруппыИсполнителей") Тогда
		
		ВидОбновления = "ГруппыИсполнителей";
		
	ИначеЕсли Параметры.Количество() = 1
	        И Параметры.Свойство("ОбъектыАвторизации") Тогда
		
		ВидОбновления = "ОбъектыАвторизации";
	Иначе
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка в процедуре %1
			           |модуля менеджера регистра сведений %2.
			           |
			           |Указаны неверные параметры.'"),
			"ОбновитьГруппировкиПользователей",
			"ГруппыЗначенийДоступа");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы()
		 Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления() Тогда
			
			УдалитьЛишниеЗаписи(ЕстьИзменения);
		КонецЕсли;
		
		Если ВидОбновления = "ПользователиИГруппыПользователей" Тогда
			
			Если Параметры.Свойство("Пользователи") Тогда
				ОбновитьПользователей(        Параметры.Пользователи, ЕстьИзменения);
				ОбновитьГруппыИсполнителей( , Параметры.Пользователи, ЕстьИзменения);
			КонецЕсли;
			
			Если Параметры.Свойство("ГруппыПользователей") Тогда
				ОбновитьГруппыПользователей(Параметры.ГруппыПользователей, ЕстьИзменения);
			КонецЕсли;
			
		ИначеЕсли ВидОбновления = "ГруппыИсполнителей" Тогда
			ОбновитьГруппыИсполнителей(Параметры.ГруппыИсполнителей, , ЕстьИзменения);
			
		ИначеЕсли ВидОбновления = "ОбъектыАвторизации" Тогда
			ОбновитьОбъектыАвторизации(Параметры.ОбъектыАвторизации, ЕстьИзменения);
		Иначе
			ОбновитьПользователей(       ,   ЕстьИзменения);
			ОбновитьГруппыПользователей( ,   ЕстьИзменения);
			ОбновитьГруппыИсполнителей(  , , ЕстьИзменения);
			ОбновитьОбъектыАвторизации(  ,   ЕстьИзменения);
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Процедура удаляет лишние данные по результату изменения состава
// типов значений и групп значений доступа.
//
Процедура ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() Тогда
		УправлениеДоступомСлужебный.УстановитьЗаполнениеДанныхДляОграниченияДоступа(Истина);
	КонецЕсли;
	
	ОбновитьГруппыПустыхЗначенийДоступа();
	УдалитьЛишниеЗаписи();
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Процедура обновляет данные регистра при изменении значений доступа.
//
// Параметры:
//  ЕстьИзменения - Булево - (возвращаемое значение) - если производилась запись,
//                  устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьДанныеРегистра(ЕстьИзменения = Неопределено) Экспорт
	
	УдалитьЛишниеЗаписи(ЕстьИзменения);
	
	ОбновитьГруппировкиПользователей( , ЕстьИзменения);
	
	ОбновитьГруппыЗначенийДоступа( , ЕстьИзменения);
	
КонецПроцедуры

// Обновляет группы значений доступа в РегистрСведений.ГруппыЗначенийДоступа.
//
// Параметры:
//  ЗначенияДоступа - СправочникОбъект
//                  - СправочникСсылка
//                  - Массив - массив значений указанных выше типов.
//                  - Неопределено - без отбора.
//                    Тип значений должен быть в составе типов измерения ЗначениеДоступа
//                    регистра сведений ГруппыЗначенийДоступа.
//                    Если передан Объект, то обновление будет только при его изменении.
//
//  ЕстьИзменения   - Булево - (возвращаемое значение) - если производилась запись,
//                    устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьГруппыЗначенийДоступа(ЗначенияДоступа = Неопределено,
                                        ЕстьИзменения   = Неопределено) Экспорт
	
	ЗначенияСИзменениямиПоТипам = Новый Соответствие;
	
	Если ЗначенияДоступа = Неопределено Тогда
		
		СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
		ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами;
		
		Запрос = Новый Запрос;
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ТекущаяТаблица.Ссылка
		|ИЗ
		|	&ТекущаяТаблица КАК ТекущаяТаблица";
		
		Для Каждого ИмяТаблицы Из ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления Цикл
			
			Запрос.Текст = СтрЗаменить(ТекстЗапроса, "&ТекущаяТаблица", ИмяТаблицы);
			// @skip-check query-in-loop - Малый цикл из одной или двух итераций
			Выборка = Запрос.Выполнить().Выбрать();
			
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяТаблицы);
			ОбновитьГруппыЗначенияДоступа(МенеджерОбъекта.ПустаяСсылка(), ЕстьИзменения, ЗначенияСИзменениямиПоТипам);
			
			Пока Выборка.Следующий() Цикл
				ОбновитьГруппыЗначенияДоступа(Выборка.Ссылка, ЕстьИзменения, ЗначенияСИзменениямиПоТипам);
			КонецЦикла;
		КонецЦикла;
		
	ИначеЕсли ТипЗнч(ЗначенияДоступа) = Тип("Массив") Тогда
		
		Для каждого ЗначениеДоступа Из ЗначенияДоступа Цикл
			ОбновитьГруппыЗначенияДоступа(ЗначениеДоступа, ЕстьИзменения, ЗначенияСИзменениямиПоТипам);
		КонецЦикла;
	Иначе
		ОбновитьГруппыЗначенияДоступа(ЗначенияДоступа, ЕстьИзменения, ЗначенияСИзменениямиПоТипам);
	КонецЕсли;
	
	УправлениеДоступомСлужебный.ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами(
		ЗначенияСИзменениямиПоТипам);
	
КонецПроцедуры

// Заполняет группы для пустых ссылок используемых типов значений доступа.
Процедура ОбновитьГруппыПустыхЗначенийДоступа()
	
	СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
	ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами;
	
	ЗначенияСИзменениямиПоТипам = Новый Соответствие;
	
	Для Каждого ИмяТаблицы Из ЗначенияДоступаСГруппами.ИменаТаблицДляОбновления Цикл
		ПустаяСсылка = ПредопределенноеЗначение(ИмяТаблицы + ".ПустаяСсылка");
		ОбновитьГруппыЗначенияДоступа(ПустаяСсылка, Неопределено, ЗначенияСИзменениямиПоТипам);
	КонецЦикла;
	
	УправлениеДоступомСлужебный.ЗапланироватьОбновлениеЗависимыхСписковПоЗначениямСГруппами(
		ЗначенияСИзменениямиПоТипам);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обновление информационной базы.

Процедура ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	// Регистрация данных не требуется.
	Возврат;
	
КонецПроцедуры

Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	ОбновитьДанныеРегистра();
	
	Параметры.ОбработкаЗавершена = Истина;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции.

// Удаляет строки, которых не должно быть, если они добавлены каким-либо способом.
Процедура УдалитьЛишниеЗаписи(ЕстьИзменения = Неопределено)
	
	СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
	ТипыГруппЗначений = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления;
	
	ТаблицаТиповГруппИЗначений = Новый ТаблицаЗначений;
	ТаблицаТиповГруппИЗначений.Колонки.Добавить("ТипЗначений",      Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип);
	ТаблицаТиповГруппИЗначений.Колонки.Добавить("ТипГруппЗначений", Метаданные.ОпределяемыеТипы.ЗначениеДоступа.Тип);
	
	Для каждого КлючИЗначение Из ТипыГруппЗначений Цикл
		Если ТипЗнч(КлючИЗначение.Ключ) = Тип("Тип") Тогда
			Продолжить;
		КонецЕсли;
		Строка = ТаблицаТиповГруппИЗначений.Добавить();
		Строка.ТипЗначений      = КлючИЗначение.Ключ;
		Строка.ТипГруппЗначений = КлючИЗначение.Значение;
	КонецЦикла;
	
	// Группы данных в регистре.
	// 0 - Стандартные значения доступа.
	// 1 - Обычные/внешние пользователи.
	// 2 - Обычные/внешние группы пользователей.
	// 3 - Группы исполнителей.
	// 4 - Объекты авторизации.
	
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТаблицаТиповГруппИЗначений", ТаблицаТиповГруппИЗначений);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ТаблицаТипов.ТипЗначений КАК ТипЗначений,
	|	ТаблицаТипов.ТипГруппЗначений КАК ТипГруппЗначений
	|ПОМЕСТИТЬ ТаблицаТиповГруппИЗначений
	|ИЗ
	|	&ТаблицаТиповГруппИЗначений КАК ТаблицаТипов
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	ТаблицаТипов.ТипЗначений,
	|	ТаблицаТипов.ТипГруппЗначений
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ГруппыЗначений.ЗначениеДоступа КАК ЗначениеДоступа,
	|	ГруппыЗначений.ГруппаЗначенийДоступа КАК ГруппаЗначенийДоступа,
	|	ГруппыЗначений.ГруппаДанных КАК ГруппаДанных
	|ИЗ
	|	(ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа КАК ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа КАК ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных КАК ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа = НЕОПРЕДЕЛЕНО
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 0
	|		И НЕ ИСТИНА В
	|					(ВЫБРАТЬ ПЕРВЫЕ 1
	|						ИСТИНА
	|					ИЗ
	|						ТаблицаТиповГруппИЗначений КАК ТаблицаТиповГруппИЗначений
	|					ГДЕ
	|						ТИПЗНАЧЕНИЯ(ТаблицаТиповГруппИЗначений.ТипЗначений) = ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа)
	|						И ТИПЗНАЧЕНИЯ(ТаблицаТиповГруппИЗначений.ТипГруппЗначений) = ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа))
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 1
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) <> ТИП(Справочник.Пользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) <> ТИП(Справочник.ВнешниеПользователи)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 1
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.Пользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.Пользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 1
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ВнешниеПользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ВнешниеПользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 2
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) <> ТИП(Справочник.ГруппыПользователей)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 2
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.Пользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 2
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ВнешниеПользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 3
	|		И (ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.Пользователи)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ВнешниеПользователи)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей))
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 3
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.Пользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыПользователей)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ВнешниеПользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 4
	|		И (ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.Пользователи)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыПользователей)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ВнешниеПользователи)
	|				ИЛИ ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ЗначениеДоступа) = ТИП(Справочник.ГруппыВнешнихПользователей))
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных = 4
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ВнешниеПользователи)
	|		И ТИПЗНАЧЕНИЯ(ГруппыЗначенийДоступа.ГруппаЗначенийДоступа) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	
	|	ОБЪЕДИНИТЬ ВСЕ
	|	
	|	ВЫБРАТЬ
	|		ГруппыЗначенийДоступа.ЗначениеДоступа,
	|		ГруппыЗначенийДоступа.ГруппаЗначенийДоступа,
	|		ГруппыЗначенийДоступа.ГруппаДанных
	|	ИЗ
	|		РегистрСведений.ГруппыЗначенийДоступа КАК ГруппыЗначенийДоступа
	|	ГДЕ
	|		ГруппыЗначенийДоступа.ГруппаДанных > 4) КАК ГруппыЗначений";
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если Не РезультатЗапроса.Пустой() Тогда
		Выборка = РезультатЗапроса.Выбрать();
		Пока Выборка.Следующий() Цикл
			НаборЗаписей = СоздатьНаборЗаписей();
			НаборЗаписей.Отбор.ЗначениеДоступа.Установить(Выборка.ЗначениеДоступа);
			НаборЗаписей.Отбор.ГруппаЗначенийДоступа.Установить(Выборка.ГруппаЗначенийДоступа);
			НаборЗаписей.Отбор.ГруппаДанных.Установить(Выборка.ГруппаДанных);
			НаборЗаписей.Записать();
			ЕстьИзменения = Истина;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// Обновляет группы значения доступа в РегистрСведений.ГруппыЗначенийДоступа.
//
// Параметры:
//  ЗначениеДоступа - СправочникСсылка.
//                    СправочникОбъект.
//                    Если передан Объект, то обновление будет только при его изменении.
//
//  ЕстьИзменения   - Булево - (возвращаемое значение) - если производилась запись,
//                    устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьГруппыЗначенияДоступа(ЗначениеДоступа, ЕстьИзменения, ЗначенияСИзменениямиПоТипам)
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТипЗначенияДоступа = ТипЗнч(ЗначениеДоступа);
	
	СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
	ЗначенияДоступаСГруппами = СвойстваВидовДоступа.ЗначенияДоступаСГруппами;
	
	СвойстваВидаДоступа = ЗначенияДоступаСГруппами.ПоТипамДляОбновления.Получить(ТипЗначенияДоступа);
	
	ЗаголовокОшибки =
		НСтр("ru = 'Ошибка при обновлении групп значений доступа.'")
		+ Символы.ПС
		+ Символы.ПС;
	
	Если СвойстваВидаДоступа = Неопределено Тогда
		ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для типа ""%1""
			           |не настроено использование групп значений доступа.'"),
			Строка(ТипЗначенияДоступа));
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Если ЗначенияДоступаСГруппами.ПоТипамСсылокДляОбновления.Получить(ТипЗначенияДоступа) = Неопределено Тогда
		Ссылка = ПользователиСлужебный.СсылкаОбъекта(ЗначениеДоступа);
		Объект = ЗначениеДоступа;
	Иначе
		Ссылка = ЗначениеДоступа;
		Объект = Неопределено;
	КонецЕсли;
	
	// Подготовка старых значений полей.
	ИмяРеквизита      = "ГруппаДоступа";
	ИмяТабличнойЧасти = "ГруппыДоступа";
	
	Если СвойстваВидаДоступа.ТипГруппЗначений = Тип("Неопределено") Тогда
		ПолеДляЗапроса = "Ссылка";
	ИначеЕсли СвойстваВидаДоступа.НесколькоГруппЗначений Тогда
		ПолеДляЗапроса = ИмяТабличнойЧасти;
	Иначе
		ПолеДляЗапроса = ИмяРеквизита;
	КонецЕсли;
	
	Попытка
		Если ЗначениеЗаполнено(Ссылка) Тогда
			СтарыеЗначения = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, ПолеДляЗапроса);
		Иначе
			СтарыеЗначения = Новый Структура(ПолеДляЗапроса, Неопределено);
		КонецЕсли;
	Исключение
		Ошибка = ИнформацияОбОшибке();
		МетаданныеТипа = Метаданные.НайтиПоТипу(ТипЗначенияДоступа);
		
		Если СвойстваВидаДоступа.ТипГруппЗначений = Тип("Неопределено") Тогда
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'У значения доступа ""%1""
				           |типа ""%2""
				           |не удалось прочитать реквизит %3 по причине:
				           |%4'"),
				Строка(ЗначениеДоступа),
				Строка(ТипЗначенияДоступа),
				"Ссылка",
				ОбработкаОшибок.КраткоеПредставлениеОшибки(Ошибка));
			ВызватьИсключение ТекстОшибки;
			
		ИначеЕсли СвойстваВидаДоступа.НесколькоГруппЗначений Тогда
			ТабличнаяЧастьМетаданные = МетаданныеТипа.ТабличныеЧасти.Найти("ГруппыДоступа");
			
			Если ТабличнаяЧастьМетаданные = Неопределено
			 ИЛИ ТабличнаяЧастьМетаданные.Реквизиты.Найти("ГруппаДоступа") = Неопределено Тогда
				
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'У типа значений доступа ""%1""
					           |не создана специальная табличная часть %2
					           |со специальным реквизитом %3.'"),
					Строка(ТипЗначенияДоступа),
					"ГруппыДоступа",
					"ГруппаДоступа");
				ВызватьИсключение ТекстОшибки;
			Иначе
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'У значения доступа ""%1""
					           |типа ""%2""
					           |не удалось прочитать табличную часть %3
					           |с реквизитом %4 по причине:
					           |%5'"),
					Строка(ЗначениеДоступа),
					Строка(ТипЗначенияДоступа),
					"ГруппыДоступа",
					"ГруппаДоступа",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(Ошибка));
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
		Иначе
			Если МетаданныеТипа.Реквизиты.Найти("ГруппаДоступа") = Неопределено Тогда
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'У типа значений доступа ""%1""
					           |не создан специальный реквизит %2.'"),
					Строка(ТипЗначенияДоступа), "ГруппаДоступа");
				ВызватьИсключение ТекстОшибки;
			Иначе
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'У значения доступа ""%1""
					           |типа ""%2""
					           |не удалось прочитать реквизит %3 по причине:
					           |%4'"),
					Строка(ЗначениеДоступа),
					Строка(ТипЗначенияДоступа),
					"ГруппаДоступа",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(Ошибка));
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
		КонецЕсли;
	КонецПопытки;
	
	// Проверка изменения объекта.
	ТребуетсяОбновление = Ложь;
	Если Объект <> Неопределено Тогда
		
		Если Объект.ЭтоНовый() Тогда
			ТребуетсяОбновление = Истина;
			
		ИначеЕсли СвойстваВидаДоступа.ТипГруппЗначений <> Тип("Неопределено") Тогда
			
			Если СвойстваВидаДоступа.НесколькоГруппЗначений Тогда
				Значение = Объект[ИмяТабличнойЧасти].Выгрузить();
				Значение.Сортировать(ИмяРеквизита);
				Если СтарыеЗначения[ИмяТабличнойЧасти] <> Неопределено Тогда
					СтарыеЗначения[ИмяТабличнойЧасти] = СтарыеЗначения[ИмяТабличнойЧасти].Выгрузить();
					СтарыеЗначения[ИмяТабличнойЧасти].Сортировать(ИмяРеквизита);
				КонецЕсли;
			Иначе
				Значение = Объект[ИмяРеквизита];
			КонецЕсли;
			
			Если НЕ ОбщегоНазначения.ДанныеСовпадают(Значение, СтарыеЗначения[ПолеДляЗапроса]) Тогда
				ТребуетсяОбновление = Истина;
			КонецЕсли;
		КонецЕсли;
		НовыеЗначения = Объект;
	Иначе
		ТребуетсяОбновление = Истина;
		НовыеЗначения = СтарыеЗначения;
	КонецЕсли;
	
	// Подготовка новых записей для обновления.
	НовыеЗаписи = СоздатьНаборЗаписей().Выгрузить();
	
	Если Константы.ОграничиватьДоступНаУровнеЗаписей.Получить() Тогда
		
		// Добавление групп значений.
		Если СвойстваВидаДоступа.ТипГруппЗначений = Тип("Неопределено") Тогда
			Запись = НовыеЗаписи.Добавить();
			Запись.ЗначениеДоступа       = Ссылка;
			Запись.ГруппаЗначенийДоступа = Ссылка;
		Иначе
			СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
			ТипыГруппЗначений = СвойстваВидовДоступа.ЗначенияДоступаСГруппами.ТипыГруппЗначенийДляОбновления;
			
			ПустаяСсылкаГруппыЗначенийДоступа = ТипыГруппЗначений.Получить(ТипЗнч(Ссылка));
			
			Если СвойстваВидаДоступа.НесколькоГруппЗначений Тогда
				Если НовыеЗначения[ИмяТабличнойЧасти] = Неопределено Тогда
					ГруппыЗначенийДоступа = Новый ТаблицаЗначений;
					ГруппыЗначенийДоступа.Колонки.Добавить("ГруппаДоступа");
				Иначе
					ГруппыЗначенийДоступа = НовыеЗначения[ИмяТабличнойЧасти].Выгрузить();
				КонецЕсли;
				Если ГруппыЗначенийДоступа.Количество() = 0 Тогда
					ГруппыЗначенийДоступа.Добавить();
				Иначе
					ГруппыЗначенийДоступа.Свернуть("ГруппаДоступа");
				КонецЕсли;
				Для каждого Строка Из ГруппыЗначенийДоступа Цикл
					Запись = НовыеЗаписи.Добавить();
					Запись.ЗначениеДоступа       = Ссылка;
					Запись.ГруппаЗначенийДоступа = Строка[ИмяРеквизита];
					Если ТипЗнч(Запись.ГруппаЗначенийДоступа) <> ТипЗнч(ПустаяСсылкаГруппыЗначенийДоступа) Тогда
						Запись.ГруппаЗначенийДоступа = ПустаяСсылкаГруппыЗначенийДоступа;
					КонецЕсли;
				КонецЦикла;
			Иначе
				Запись = НовыеЗаписи.Добавить();
				Запись.ЗначениеДоступа       = Ссылка;
				Запись.ГруппаЗначенийДоступа = НовыеЗначения[ИмяРеквизита];
				Если ТипЗнч(Запись.ГруппаЗначенийДоступа) <> ТипЗнч(ПустаяСсылкаГруппыЗначенийДоступа) Тогда
					Запись.ГруппаЗначенийДоступа = ПустаяСсылкаГруппыЗначенийДоступа;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Если Объект = Неопределено Тогда
		ДополнительныеСвойства = Неопределено;
	Иначе
		ДополнительныеСвойства = Новый Структура("ВедущийОбъектПередЗаписью", Объект);
	КонецЕсли;
	
	ФиксированныйОтбор = Новый Структура;
	ФиксированныйОтбор.Вставить("ЗначениеДоступа", Ссылка);
	ФиксированныйОтбор.Вставить("ГруппаДанных", 0);
	
	Данные = Новый Структура;
	Данные.Вставить("МенеджерРегистра",       РегистрыСведений.ГруппыЗначенийДоступа);
	Данные.Вставить("НовыеЗаписи",            НовыеЗаписи);
	Данные.Вставить("ФиксированныйОтбор",     ФиксированныйОтбор);
	Данные.Вставить("ДополнительныеСвойства", ДополнительныеСвойства);
	
	ЕстьТекущиеИзменения = Ложь;
	НачатьТранзакцию();
	Попытка
		УправлениеДоступомСлужебный.ОбновитьНаборыЗаписей(Данные, ЕстьТекущиеИзменения);
		Если ЕстьТекущиеИзменения Тогда
			ЕстьИзменения = Истина;
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Если Не ТребуетсяОбновление И Не ЕстьТекущиеИзменения Тогда
		Возврат;
	КонецЕсли;
	
	Если СвойстваВидаДоступа.ТипГруппЗначений <> Тип("Неопределено")
	   И (Объект = Неопределено Или Не Объект.ЭтоНовый()) Тогда
		
		ТекущаяСсылка = ЗначенияСИзменениямиПоТипам.Получить(СвойстваВидаДоступа.ТипЗначений);
		
		Если ТекущаяСсылка = Неопределено Тогда
			ЗначенияСИзменениямиПоТипам.Вставить(СвойстваВидаДоступа.ТипЗначений, Ссылка);
			
		ИначеЕсли ТипЗнч(ТекущаяСсылка) = СвойстваВидаДоступа.ТипЗначений Тогда
			ЗначенияСИзменениямиПоТипам.Вставить(СвойстваВидаДоступа.ТипЗначений, Истина);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Обновляет группировки пользователей для проверки разрешенных значений
// по видам доступа Пользователи и ВнешниеПользователи.
//
// <Состав поля ЗначениеДоступа>    <Состав поля ГруппаЗначенийДоступа>.
//                               <Состав поля ГруппаДанных>.
//
// А) для вида доступа Пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийПользователь}.
//
// Пользователь                  1 - Тот же Пользователь.
//
//                               1 - Группа пользователей
//                                   того же пользователя.
//
// Б) для вида доступа Внешние пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийВнешнийПользователь}.
//
// Внешний пользователь          1 - Тот же Внешний пользователь.
//
//                               1 - Группа внешних пользователей
//                                   того же внешнего пользователя.
//
Процедура ОбновитьПользователей(Пользователи1 = Неопределено,
                                ЕстьИзменения = Неопределено)
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	СоставыГруппПользователей.Пользователь КАК ЗначениеДоступа,
	|	СоставыГруппПользователей.ГруппаПользователей КАК ГруппаЗначенийДоступа,
	|	1 КАК ГруппаДанных,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)
	|	И &УсловиеОтбораПользователей1
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	СоставыГруппПользователей.Пользователь,
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	1,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.ВнешниеПользователи)
	|	И &УсловиеОтбораПользователей1";
	
	// Подготовка выбираемых полей с необязательным отбором.
	Поля = Новый Массив; 
	Поля.Добавить(Новый Структура("ЗначениеДоступа",       "&УсловиеОтбораПользователей2"));
	Поля.Добавить(Новый Структура("ГруппаЗначенийДоступа"));
	Поля.Добавить(Новый Структура("ГруппаДанных",          "&УсловиеОтбораГруппОбновляемыхДанных"));
	
	Запрос = Новый Запрос;
	Запрос.Текст = УправлениеДоступомСлужебный.ТекстЗапросаВыбораИзменений(
		ТекстЗапроса, Поля, "РегистрСведений.ГруппыЗначенийДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, Пользователи1, "Пользователи",
		"&УсловиеОтбораПользователей1:СоставыГруппПользователей.Пользователь
		|&УсловиеОтбораПользователей2:СтарыеДанные.ЗначениеДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, 1, "ГруппаДанных",
		"&УсловиеОтбораГруппОбновляемыхДанных:СтарыеДанные.ГруппаДанных");
	
	Данные = Новый Структура;
	Данные.Вставить("МенеджерРегистра",      РегистрыСведений.ГруппыЗначенийДоступа);
	Данные.Вставить("ИзмененияСоставаСтрок", Запрос.Выполнить().Выгрузить());
	Данные.Вставить("ФиксированныйОтбор",    Новый Структура("ГруппаДанных", 1));
	
	УправлениеДоступомСлужебный.ОбновитьРегистрСведений(Данные, ЕстьИзменения);
	
КонецПроцедуры

// Обновляет группировки пользователей для проверки разрешенных значений
// по видам доступа Пользователи и ВнешниеПользователи.
//
// <Состав поля ЗначениеДоступа>    <Состав поля ГруппаЗначенийДоступа>.
//                               <Состав поля ГруппаДанных>.
//
// А) для вида доступа Пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийПользователь}.
//
// Группа пользователей          2 - Та же Группа пользователей.
//
//                               2 - Пользователь
//                                   той же группы пользователей.
//
// Б) для вида доступа Внешние пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийВнешнийПользователь}.
//
// Группа внешних пользователей  2 - Та же Группа внешних пользователей.
//
//                               2 - Внешний пользователь
//                                   той же группы внешних пользователей.
//
//
Процедура ОбновитьГруппыПользователей(ГруппыПользователей = Неопределено,
                                      ЕстьИзменения       = Неопределено)
	
	УстановитьПривилегированныйРежим(Истина);
	
	ТекстЗапроса =
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	СоставыГруппПользователей.ГруппаПользователей КАК ЗначениеДоступа,
	|	СоставыГруппПользователей.ГруппаПользователей КАК ГруппаЗначенийДоступа,
	|	2 КАК ГруппаДанных,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)
	|	И &УсловиеОтбораГруппПользователей1
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	СоставыГруппПользователей.Пользователь,
	|	2,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей)
	|	И ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.Пользователи)
	|	И &УсловиеОтбораГруппПользователей1
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	2,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыВнешнихПользователей)
	|	И &УсловиеОтбораГруппПользователей1
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	СоставыГруппПользователей.Пользователь,
	|	2,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыВнешнихПользователей)
	|	И ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.ВнешниеПользователи)
	|	И &УсловиеОтбораГруппПользователей1";
	
	// Подготовка выбираемых полей с необязательным отбором.
	Поля = Новый Массив; 
	Поля.Добавить(Новый Структура("ЗначениеДоступа",         "&УсловиеОтбораГруппПользователей2"));
	Поля.Добавить(Новый Структура("ГруппаЗначенийДоступа"));
	Поля.Добавить(Новый Структура("ГруппаДанных",            "&УсловиеОтбораГруппОбновляемыхДанных"));
	
	Запрос = Новый Запрос;
	Запрос.Текст = УправлениеДоступомСлужебный.ТекстЗапросаВыбораИзменений(
		ТекстЗапроса, Поля, "РегистрСведений.ГруппыЗначенийДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, ГруппыПользователей, "ГруппыПользователей",
		"&УсловиеОтбораГруппПользователей1:СоставыГруппПользователей.ГруппаПользователей
		|&УсловиеОтбораГруппПользователей2:СтарыеДанные.ЗначениеДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, 2, "ГруппаДанных",
		"&УсловиеОтбораГруппОбновляемыхДанных:СтарыеДанные.ГруппаДанных");
	
	Данные = Новый Структура;
	Данные.Вставить("МенеджерРегистра",      РегистрыСведений.ГруппыЗначенийДоступа);
	Данные.Вставить("ИзмененияСоставаСтрок", Запрос.Выполнить().Выгрузить());
	Данные.Вставить("ФиксированныйОтбор",    Новый Структура("ГруппаДанных", 2));
	
	УправлениеДоступомСлужебный.ОбновитьРегистрСведений(Данные, ЕстьИзменения);
	
КонецПроцедуры

// Обновляет группировки пользователей для проверки разрешенных значений
// по видам доступа Пользователи и ВнешниеПользователи.
//
// <Состав поля ЗначениеДоступа>    <Состав поля ГруппаЗначенийДоступа>.
//                               <Состав поля ГруппаДанных>.
//
// А) для вида доступа Пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийПользователь}.
//
// Группа исполнителей           3 - Пользователь
//                                   той же группы исполнителей.
//
//                               3 - Группа пользователей пользователя
//                                   той же группы исполнителей.
//
// Б) для вида доступа Внешние пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийВнешнийПользователь}.
//
// Группа исполнителей           3 - Внешний пользователь
//                                   той же группы исполнителей.
//
//                               3 - Группа внешних пользователей
//                                   внешнего пользователя
//                                   той же группы исполнителей.
//
Процедура ОбновитьГруппыИсполнителей(ГруппыИсполнителей = Неопределено,
                                     Исполнители        = Неопределено,
                                     ЕстьИзменения      = Неопределено)
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Подготовка таблицы дополнительных групп пользователей -
	// групп исполнителей (например, задач).
	
	Запрос = Новый Запрос;
	Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	
	Если ГруппыИсполнителей = Неопределено
	   И Исполнители        = Неопределено Тогда
	
		СодержаниеПараметра = Неопределено;
		ЗначениеПараметра   = Неопределено;
	
	ИначеЕсли ГруппыИсполнителей <> Неопределено Тогда
		СодержаниеПараметра = "ГруппыИсполнителей";
		ЗначениеПараметра   = ГруппыИсполнителей;
		
	ИначеЕсли Исполнители <> Неопределено Тогда
		СодержаниеПараметра = "Исполнители";
		ЗначениеПараметра   = Исполнители;
	Иначе
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка в процедуре %1
			           |модуля менеджера регистра сведений %2.
			           |
			           |Указаны неверные параметры.'"),
			"ОбновитьГруппыИсполнителей",
			"ГруппыЗначенийДоступа");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	НетГруппИсполнителей = Истина;
	ИнтеграцияПодсистемБСП.ПриОпределенииГруппИсполнителей(Запрос.МенеджерВременныхТаблиц,
		СодержаниеПараметра, ЗначениеПараметра, НетГруппИсполнителей);
	
	Если НетГруппИсполнителей Тогда
		НаборЗаписей = СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.ГруппаДанных.Установить(3);
		НаборЗаписей.Прочитать();
		Если НаборЗаписей.Количество() > 0 Тогда
			НаборЗаписей.Очистить();
			НаборЗаписей.Записать();
			ЕстьИзменения = Истина;
		КонецЕсли;
		Возврат;
	КонецЕсли;
	
	// Подготовка отобранных связей исполнителей и групп исполнителей.
	Запрос.УстановитьПараметр("ПустыеСсылкиГруппЗначений",
		УправлениеДоступомСлужебныйПовтИсп.ТаблицаПустыхСсылокУказанныхТипов(
			"РегистрСведений.ГруппыЗначенийДоступа.Измерение.ГруппаЗначенийДоступа").Получить());
	
	ТекстЗапросовВременныхТаблиц =
	"ВЫБРАТЬ
	|	ПустыеСсылкиГруппЗначений.ПустаяСсылка
	|ПОМЕСТИТЬ ПустыеСсылкиГруппЗначений
	|ИЗ
	|	&ПустыеСсылкиГруппЗначений КАК ПустыеСсылкиГруппЗначений
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	ПустыеСсылкиГруппЗначений.ПустаяСсылка
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ТаблицаГруппИсполнителей.ГруппаИсполнителей,
	|	ТаблицаГруппИсполнителей.Пользователь
	|ПОМЕСТИТЬ ПользователиГруппИсполнителей
	|ИЗ
	|	ТаблицаГруппИсполнителей КАК ТаблицаГруппИсполнителей
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПустыеСсылкиГруппЗначений КАК ПустыеСсылкиГруппЗначений
	|		ПО (ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) = ТИПЗНАЧЕНИЯ(ПустыеСсылкиГруппЗначений.ПустаяСсылка))
	|			И ТаблицаГруппИсполнителей.ГруппаИсполнителей <> ПустыеСсылкиГруппЗначений.ПустаяСсылка
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ГруппыПользователей)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.Пользователи)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ВнешниеПользователи)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.Пользователь) = ТИП(Справочник.Пользователи)
	|	И ТаблицаГруппИсполнителей.Пользователь <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ТаблицаГруппИсполнителей.ГруппаИсполнителей,
	|	ТаблицаГруппИсполнителей.Пользователь КАК ВнешнийПользователь
	|ПОМЕСТИТЬ ВнешниеПользователиГруппИсполнителей
	|ИЗ
	|	ТаблицаГруппИсполнителей КАК ТаблицаГруппИсполнителей
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПустыеСсылкиГруппЗначений КАК ПустыеСсылкиГруппЗначений
	|		ПО (ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) = ТИПЗНАЧЕНИЯ(ПустыеСсылкиГруппЗначений.ПустаяСсылка))
	|			И ТаблицаГруппИсполнителей.ГруппаИсполнителей <> ПустыеСсылкиГруппЗначений.ПустаяСсылка
	|ГДЕ
	|	ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ГруппыПользователей)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.Пользователи)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ГруппыВнешнихПользователей)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.ГруппаИсполнителей) <> ТИП(Справочник.ВнешниеПользователи)
	|	И ТИПЗНАЧЕНИЯ(ТаблицаГруппИсполнителей.Пользователь) = ТИП(Справочник.ВнешниеПользователи)
	|	И ТаблицаГруппИсполнителей.Пользователь <> ЗНАЧЕНИЕ(Справочник.ВнешниеПользователи.ПустаяСсылка)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|УНИЧТОЖИТЬ ТаблицаГруппИсполнителей";
	
	Если ГруппыИсполнителей = Неопределено
	   И Исполнители <> Неопределено Тогда
		
		// АПК:96-выкл - №434 Использование ОБЪЕДИНИТЬ допустимо, так как
		// строки не должны повторятся и объем данных небольшой (от единиц до сотен).
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПользователиГруппИсполнителей.ГруппаИсполнителей
		|ИЗ
		|	ПользователиГруппИсполнителей КАК ПользователиГруппИсполнителей
		|
		|ОБЪЕДИНИТЬ
		|
		|ВЫБРАТЬ
		|	ВнешниеПользователиГруппИсполнителей.ГруппаИсполнителей
		|ИЗ
		|	ВнешниеПользователиГруппИсполнителей КАК ВнешниеПользователиГруппИсполнителей";
		// АПК:96-вкл.
		
		Запрос.Текст = ТекстЗапросовВременныхТаблиц + "
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|" + ТекстЗапроса;
		
		РезультатыЗапросов = Запрос.ВыполнитьПакет();
		Количество = РезультатыЗапросов.Количество();
		
		ГруппыИсполнителей = РезультатыЗапросов[Количество-1].Выгрузить().ВыгрузитьКолонку("ГруппаИсполнителей");
		ТекстЗапросовВременныхТаблиц = Неопределено;
	КонецЕсли;
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ПользователиГруппИсполнителей.ГруппаИсполнителей КАК ЗначениеДоступа,
	|	ПользователиГруппИсполнителей.Пользователь КАК ГруппаЗначенийДоступа,
	|	3 КАК ГруппаДанных,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	ПользователиГруппИсполнителей КАК ПользователиГруппИсполнителей
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ПользователиГруппИсполнителей.ГруппаИсполнителей,
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	3,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	ПользователиГруппИсполнителей КАК ПользователиГруппИсполнителей
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|		ПО ПользователиГруппИсполнителей.Пользователь = СоставыГруппПользователей.Пользователь
	|			И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыПользователей))
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	ВнешниеПользователиГруппИсполнителей.ГруппаИсполнителей,
	|	ВнешниеПользователиГруппИсполнителей.ВнешнийПользователь,
	|	3,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	ВнешниеПользователиГруппИсполнителей КАК ВнешниеПользователиГруппИсполнителей
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ВнешниеПользователиГруппИсполнителей.ГруппаИсполнителей,
	|	СоставыГруппПользователей.ГруппаПользователей,
	|	3,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	ВнешниеПользователиГруппИсполнителей КАК ВнешниеПользователиГруппИсполнителей
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|		ПО ВнешниеПользователиГруппИсполнителей.ВнешнийПользователь = СоставыГруппПользователей.Пользователь
	|			И (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.ГруппаПользователей) = ТИП(Справочник.ГруппыВнешнихПользователей))";
	
	// Подготовка выбираемых полей с необязательным отбором.
	Поля = Новый Массив; 
	Поля.Добавить(Новый Структура("ЗначениеДоступа",         "&УсловиеОтбораГруппИсполнителей"));
	Поля.Добавить(Новый Структура("ГруппаЗначенийДоступа"));
	Поля.Добавить(Новый Структура("ГруппаДанных",            "&УсловиеОтбораГруппОбновляемыхДанных"));
	
	Запрос.Текст = УправлениеДоступомСлужебный.ТекстЗапросаВыбораИзменений(
		ТекстЗапроса, Поля, "РегистрСведений.ГруппыЗначенийДоступа", ТекстЗапросовВременныхТаблиц);
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, ГруппыИсполнителей, "ГруппыИсполнителей",
		"&УсловиеОтбораГруппИсполнителей:СтарыеДанные.ЗначениеДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, 3, "ГруппаДанных",
		"&УсловиеОтбораГруппОбновляемыхДанных:СтарыеДанные.ГруппаДанных");
	
	Данные = Новый Структура;
	Данные.Вставить("МенеджерРегистра",      РегистрыСведений.ГруппыЗначенийДоступа);
	Данные.Вставить("ИзмененияСоставаСтрок", Запрос.Выполнить().Выгрузить());
	Данные.Вставить("ФиксированныйОтбор",    Новый Структура("ГруппаДанных", 3));
	
	УправлениеДоступомСлужебный.ОбновитьРегистрСведений(Данные, ЕстьИзменения);
	
КонецПроцедуры

// Обновляет группировки пользователей для проверки разрешенных значений
// по видам доступа Пользователи и ВнешниеПользователи.
//
// <Состав поля ЗначениеДоступа>    <Состав поля ГруппаЗначенийДоступа>.
//                               <Состав поля ГруппаДанных>.
//
// Для вида доступа Внешние пользователи:
// {сравнение с Т.<поле>}           {Сравнение с ЗначенияГруппДоступа.ЗначениеДоступа}.
//                                  {Сравнение с &ТекущийВнешнийПользователь}.
//
// Объект авторизации            4 - Внешний пользователь
//                                   того же объекта авторизации.
//
//                               4 - Группа внешних пользователей
//                                   внешнего пользователя
//                                   того же объекта авторизации.
//
Процедура ОбновитьОбъектыАвторизации(ОбъектыАвторизации = Неопределено, ЕстьИзменения = Неопределено)
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ПустыеСсылкиЗначений",
		УправлениеДоступомСлужебныйПовтИсп.ТаблицаПустыхСсылокУказанныхТипов(
			"РегистрСведений.ГруппыЗначенийДоступа.Измерение.ЗначениеДоступа").Получить());
	
	ТекстЗапросовВременныхТаблиц =
	"ВЫБРАТЬ
	|	ПустыеСсылкиЗначений.ПустаяСсылка
	|ПОМЕСТИТЬ ПустыеСсылкиЗначений
	|ИЗ
	|	&ПустыеСсылкиЗначений КАК ПустыеСсылкиЗначений
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	ПустыеСсылкиЗначений.ПустаяСсылка";
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ВЫРАЗИТЬ(СоставыГруппПользователей.Пользователь КАК Справочник.ВнешниеПользователи).ОбъектАвторизации КАК ЗначениеДоступа,
	|	СоставыГруппПользователей.ГруппаПользователей КАК ГруппаЗначенийДоступа,
	|	4 КАК ГруппаДанных,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	РегистрСведений.СоставыГруппПользователей КАК СоставыГруппПользователей
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.ВнешниеПользователи КАК ВнешниеПользователи
	|		ПО (ТИПЗНАЧЕНИЯ(СоставыГруппПользователей.Пользователь) = ТИП(Справочник.ВнешниеПользователи))
	|			И СоставыГруппПользователей.Пользователь = ВнешниеПользователи.Ссылка
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПустыеСсылкиЗначений КАК ПустыеСсылкиЗначений
	|		ПО (ТИПЗНАЧЕНИЯ(ВнешниеПользователи.ОбъектАвторизации) = ТИПЗНАЧЕНИЯ(ПустыеСсылкиЗначений.ПустаяСсылка))
	|			И (ВнешниеПользователи.ОбъектАвторизации <> ПустыеСсылкиЗначений.ПустаяСсылка)
	|ГДЕ
	|	&УсловиеОтбораОбъектовАвторизации1";
	
	// Подготовка выбираемых полей с необязательным отбором.
	Поля = Новый Массив; 
	Поля.Добавить(Новый Структура("ЗначениеДоступа",         "&УсловиеОтбораОбъектовАвторизации2"));
	Поля.Добавить(Новый Структура("ГруппаЗначенийДоступа"));
	Поля.Добавить(Новый Структура("ГруппаДанных",            "&УсловиеОтбораГруппОбновляемыхДанных"));
	
	Запрос.Текст = УправлениеДоступомСлужебный.ТекстЗапросаВыбораИзменений(
		ТекстЗапроса, Поля, "РегистрСведений.ГруппыЗначенийДоступа", ТекстЗапросовВременныхТаблиц);
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, ОбъектыАвторизации, "ОбъектыАвторизации",
		"&УсловиеОтбораОбъектовАвторизации1:ВнешниеПользователи.ОбъектАвторизации
		|&УсловиеОтбораОбъектовАвторизации2:СтарыеДанные.ЗначениеДоступа");
	
	УправлениеДоступомСлужебный.УстановитьУсловиеОтбораВЗапросе(Запрос, 4, "ГруппаДанных",
		"&УсловиеОтбораГруппОбновляемыхДанных:СтарыеДанные.ГруппаДанных");
	
	Данные = Новый Структура;
	Данные.Вставить("МенеджерРегистра",      РегистрыСведений.ГруппыЗначенийДоступа);
	Данные.Вставить("ИзмененияСоставаСтрок", Запрос.Выполнить().Выгрузить());
	Данные.Вставить("ФиксированныйОтбор",    Новый Структура("ГруппаДанных", 4));
	
	УправлениеДоступомСлужебный.ОбновитьРегистрСведений(Данные, ЕстьИзменения);
	
КонецПроцедуры

#КонецОбласти

#КонецЕсли